package com.tbit.uqbike.service.business.impl;

import cn.hutool.core.lang.UUID;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.tbit.common.constant.CommonConstant;
import com.tbit.uqbike.constant.*;
import com.tbit.uqbike.manager.exception.BaseException;
import com.tbit.uqbike.object.pojo.Role;
import com.tbit.uqbike.object.pojo.RoleMenu;
import com.tbit.uqbike.object.pojo.dto.RoleCopyAddDTO;
import com.tbit.uqbike.object.value.LoginInfo;
import com.tbit.common.entity.view.Result;
import com.tbit.uqbike.service.business.RoleService;
import com.tbit.uqbike.webmanager.dao.core.RoleDao;
import com.tbit.uqbike.webmanager.dao.core.RoleMenuDao;
import com.tbit.uqbike.webmanager.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.servlet.support.RequestContext;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 角色 业务层处理
 *
 * @author jing
 */
@Service
@Slf4j
public class RoleServiceImpl implements RoleService {
    @Autowired
    private RoleDao roleDao;

    @Autowired
    private RoleMenuDao roleMenuDao;


    /**
     * 根据条件分页查询角色数据
     *
     * @param role 角色信息
     * @return 角色数据集合信息
     */
    @Override
    public List<Role> selectRoleList(Role role) {
        Map<String, Integer> map = getRoleConfigMap();
        List<Role> roles = roleDao.selectRoleList(role);
        for (Role role1 : roles) {
            setRoleByRoleConfigMap(map, role1);
        }
        return roles;
    }

    /**
     * 根据用户ID查询权限
     *
     * @param userId 用户ID
     * @return 权限列表
     */
    @Override
    public Set<String> selectRolePermissionByUserId(Integer userId) {
        List<Role> perms = roleDao.selectRolePermissionByUserId(userId);
        Set<String> permsSet = new HashSet<>();
        for (Role perm : perms) {
            if (StringUtils.isNotNull(perm)) {
                permsSet.addAll(Arrays.asList(perm.getRoleKey().trim().split(",")));
            }
        }
        return permsSet;
    }

    /**
     * 查询所有角色
     *
     * @return 角色列表
     */
    @Override
    public List<Role> selectRoleAll(Role role) {
        return selectRoleList(role);
    }

    /**
     * 根据用户ID获取角色选择框列表
     *
     * @param userId 用户ID
     * @return 选中角色ID列表
     */
    @Override
    public List<Integer> selectRoleListByUserId(Integer userId) {
        return roleDao.selectRoleListByUserId(userId);
    }

    /**
     * 通过角色ID查询角色
     *
     * @param roleId 角色ID
     * @return 角色对象信息
     */
    @Override
    public Role selectRoleById(Integer roleId) {
        Role role = roleDao.selectRoleById(roleId);
        Map<String, Integer> roleConfigMap = getRoleConfigMap();
        setRoleByRoleConfigMap(roleConfigMap, role);
        return role;
    }

    /**
     * 校验角色名称是否唯一
     *
     * @param role 角色信息
     * @return 结果
     */
    @Override
    public String checkRoleNameUnique(Role role) {
        Integer roleId = StringUtils.isNull(role.getRoleId()) ? -1 : role.getRoleId();
        Role info = roleDao.checkRoleNameUnique(role.getRoleName(), role.getAccountId());
        if (StringUtils.isNotNull(info) && !info.getRoleId().equals(roleId)) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }

    @Override
    public String checkRoleValueUnique(Role role) {
        Integer roleId = StringUtils.isNull(role.getRoleId()) ? -1 : role.getRoleId();
        Role info = roleDao.checkRoleValueUnique(role.getRoleValue());
        if (StringUtils.isNotNull(info) && !info.getRoleId().equals(roleId)) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }

    /**
     * 校验角色权限是否唯一
     *
     * @param role 角色信息
     * @return 结果
     */
    @Override
    public String checkRoleKeyUnique(Role role) {
        Integer roleId = StringUtils.isNull(role.getRoleId()) ? -1 : role.getRoleId();
        Role info = roleDao.checkRoleKeyUnique(role.getRoleKey());
        if (StringUtils.isNotNull(info) && !info.getRoleId().equals(roleId)) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }

    @Override
    public String checkRoleLevelCodeUnique(Role role) {
        Integer roleId = StringUtils.isNull(role.getRoleId()) ? -1 : role.getRoleId();
        Role info = roleDao.checkRoleLevelCodeUnique(role.getRoleLevel(), role.getRoleCode());
        if (StringUtils.isNotNull(info) && !info.getRoleId().equals(roleId)) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }

    /**
     * 校验角色是否允许操作
     *
     * @param role 角色信息
     */
    @Override
    public void checkRoleAllowed(Role role) {
        if (StringUtils.isNotNull(role.getRoleId()) && role.isAdmin()) {
            throw new BaseException("super_administrator_role_is_not_allowed");
        }
    }

    /**
     * 通过角色ID查询角色使用数量
     *
     * @param roleId 角色ID
     * @return 结果
     */
    @Override
    public int countUserRoleByRoleId(Integer roleId) {
        return roleDao.countUserRoleByRoleId(roleId);
    }

    /**
     * 新增保存角色信息
     *
     * @param role 角色信息
     * @return 结果
     */
    @Override
    //@Transactional
    public int insertRole(Role role) {
        // 新增角色信息
        role.setRoleId(Integer.valueOf(role.getRoleValue()));
        //更新运维端权限
        replaceRoleConfig(role);
        return roleDao.insertRole(role);
    }

    /**
     * 修改保存角色信息
     *
     * @param role 角色信息
     * @return 结果
     */
    @Override
    //@Transactional
    public int updateRole(Role role) {
        Integer roleId = role.getRoleId();
        if (isDefaultRole(roleId)) {
            List<RoleConfig> roleConfigs = roleDao.selectRoleConfigListByRoleId(roleId);
            log.info("默认角色id：{}，进行了角色修改操作，原运维端权限列表：{}，当前入参：{}", roleId, JSON.toJSONString(roleConfigs), JSON.toJSONString(role));
        }
        //更新运维端权限
        replaceRoleConfig(role);
        // 修改角色信息
        return roleDao.updateRole(role);
    }

    /**
     * 修改角色状态
     *
     * @param role 角色信息
     * @return 结果
     */
    @Override
    public int updateRoleStatus(Role role) {
        return roleDao.updateRole(role);
    }

    @Override
    public int bindPerm(Role role) {
        //修改默认角色权限时，要打印前后修改的权限
        Integer roleId = role.getRoleId();
        if (isDefaultRole(roleId)) {
            List<Integer> menuIds = roleMenuDao.selectMenuIdListByRoleId(roleId);
            log.info("默认角色id：{}，进行了菜单权限绑定操作，原绑定菜单列表：{}，修改后绑定菜单列表：{}，当前入参：{}", roleId, JSON.toJSONString(menuIds), JSON.toJSONString(role.getMenuIds()), JSON.toJSONString(role));
        }
        //更新运维端权限
        replaceRoleConfig(role);
        // 删除角色与菜单关联
        roleMenuDao.deleteRoleMenuByRoleId(roleId);
        return insertRoleMenu(role);
    }


    /**
     * 新增角色菜单信息
     *
     * @param role 角色对象
     */
    public int insertRoleMenu(Role role) {
        int rows = 1;
        // 新增用户与角色管理
        List<RoleMenu> list = new ArrayList<RoleMenu>();
        for (Integer menuId : role.getMenuIds()) {
            RoleMenu rm = new RoleMenu();
            rm.setRoleId(role.getRoleId());
            rm.setMenuId(menuId);
            list.add(rm);
        }
        if (list.size() > 0) {
            rows = roleMenuDao.batchRoleMenu(list);
        }
        return rows;
    }


    /**
     * 通过角色ID删除角色
     *
     * @param roleId 角色ID
     * @return 结果
     */
    @Override
    //@Transactional
    public int deleteRoleById(Integer roleId) {
        // 删除角色与菜单关联
        roleMenuDao.deleteRoleMenuByRoleId(roleId);
        roleDao.deleteRoleConfig(roleId);
        return roleDao.deleteRoleById(roleId);
    }

    /**
     * 批量删除角色信息
     *
     * @param roleIds 需要删除的角色ID
     * @return 结果
     */
    @Override
    //@Transactional
    public int deleteRoleByIds(Integer[] roleIds) {
        for (Integer roleId : roleIds) {
            checkRoleAllowed(new Role(roleId));
            Role role = selectRoleById(roleId);
            if (countUserRoleByRoleId(roleId) > 0) {
                throw new BaseException(String.format("%1$s已分配,不能删除", role.getRoleName()));
            }
        }
        // 删除角色与菜单关联
        roleMenuDao.deleteRoleMenu(roleIds);
        for (Integer roleId : roleIds) {
            roleDao.deleteRoleConfig(roleId);
        }
        return roleDao.deleteRoleByIds(roleIds);
    }

    @Override
    public Integer selectInsertRoleId() {
        return roleDao.selectInsertRoleId();
    }

    @Override
    public boolean isDefaultRole(Integer roleId) {
        return roleDao.isDefaultRole(roleId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Integer> copyAdd(RoleCopyAddDTO roleCodyDTO, RequestContext context) {
        Role addRole = new Role();
        Integer roleId = roleDao.selectInsertRoleId();
        addRole.setRoleId(roleId);
        addRole.setRoleCode(roleId.toString());
        addRole.setRoleValue(roleId.toString());
        addRole.setRoleKey(roleId + "_" + UUID.randomUUID());
        if (UserConstants.NOT_UNIQUE.equals(this.checkRoleNameUnique(addRole))) {
            return Result.error(context.getMessage("insert_role_name_exists"));
        } else if (UserConstants.NOT_UNIQUE.equals(this.checkRoleKeyUnique(addRole))) {
            return Result.error(context.getMessage("insert_role_key_exists"));
        } else if (UserConstants.NOT_UNIQUE.equals(this.checkRoleValueUnique(addRole))) {
            return Result.error(context.getMessage("insert_role_value_exists"));
        } else if (UserConstants.NOT_UNIQUE.equals(this.checkRoleLevelCodeUnique(addRole))) {
            return Result.error(context.getMessage("insert_role_level_code_exists"));
        }
        //复制角色权限
        Role copiedRole = this.selectRoleById(roleCodyDTO.getCopiedRoleId());
        Integer count = roleDao.checkRoleLevelDuplicateName(roleCodyDTO.getAccountId(), roleCodyDTO.getRoleName(), copiedRole.getRoleLevel());
        if (count > 0) {
            return Result.error("当前角色等级下角色名称重复");
        }
        addRole.setAccountId(roleCodyDTO.getAccountId());
        addRole.setRoleName(roleCodyDTO.getRoleName());
        addRole.setRoleSort(copiedRole.getRoleSort());
        addRole.setLogin(copiedRole.getLogin());
        addRole.setRoleLevel(copiedRole.getRoleLevel());
        addRole.setChangeBattery(copiedRole.getChangeBattery());
        addRole.setScheduling(copiedRole.getScheduling());
        addRole.setLockVehicle(copiedRole.getLockVehicle());
        addRole.setOperatingDistance(copiedRole.getOperatingDistance());
        addRole.setLookBattery(copiedRole.getLookBattery());
        this.insertRole(addRole);
        //复制菜单权限
        List<Integer> menuIdList = roleMenuDao.selectMenuIdListByRoleId(copiedRole.getRoleId());
        Optional.ofNullable(menuIdList)
                .filter(CollectionUtils::isNotEmpty)
                .map(list -> list.stream()
                        .map(x -> {
                            RoleMenu roleMenu = new RoleMenu();
                            roleMenu.setMenuId(x);
                            roleMenu.setRoleId(addRole.getRoleId());
                            return roleMenu;
                        }).collect(Collectors.toList()))
                .ifPresent(roleMenuDao::batchRoleMenu);
        return Result.success(addRole.getRoleId());
    }

    /**
     * 更新运维端权限
     *
     * @param role
     */
    public void replaceRoleConfig(Role role) {
        //换电权限
        Integer changeBattery = role.getChangeBattery();
        //调度权限
        Integer scheduling = role.getScheduling();
        //开锁车权限
        Integer lockVehicle = role.getLockVehicle();
        //操作距离权限
        Integer operatingDistance = role.getOperatingDistance();
        //运维端查看车辆电量权限
        Integer lookBattery = role.getLookBattery();
        if (changeBattery != null) {
            roleDao.replaceRoleConfig(RoleConfigConstant.MAIN_CHANGE_BATTERY, role.getRoleId(), changeBattery);
        }
        if (scheduling != null) {
            roleDao.replaceRoleConfig(RoleConfigConstant.MAIN_SCHEDULING, role.getRoleId(), scheduling);
        }
        if (lockVehicle != null) {
            roleDao.replaceRoleConfig(RoleConfigConstant.MAIN_LOCK_VEHICLE, role.getRoleId(), lockVehicle);
        }
        if (operatingDistance != null) {
            roleDao.replaceRoleConfig(RoleConfigConstant.MAIN_OPERATING_DISTANCE, role.getRoleId(), operatingDistance);
        }
        if (lookBattery != null) {
            roleDao.replaceRoleConfig(RoleConfigConstant.MAIN_LOOK_BATTERY, role.getRoleId(), lookBattery);
        }
        Integer superviseMachine = role.getSuperviseMachine();
        if (superviseMachine != null) {
            roleDao.replaceRoleConfig(RoleConfigConstant.SUPERVISE_MACHINE, role.getRoleId(), superviseMachine);
        }
        //修改运维端权限通知运维端删除角色token
        String url = OperaPswConstant.ACCOUNT_OPERA_MAIN_URL + ServiceUrlConstant.MAIN_UPDATE_ROLE_NOTICE + "?roleId=" + role.getRoleId();
        String res = HttpUtil.get(url);
        log.info("调用url:{},运维端返回:{}", url, res);
    }

    /**
     * 获取运维角色权限map
     *
     * @return
     */
    public Map<String, Integer> getRoleConfigMap() {
        //查询所有角色权限
        List<RoleConfig> roleConfigs = roleDao.selectRoleConfigAll();
        Map<String, Integer> map = new HashMap<>();
        for (RoleConfig roleConfig : roleConfigs) {
            map.put(roleConfig.getRoleId() + "_" + roleConfig.getParamKey(), roleConfig.getParamValue());
        }
        return map;
    }

    /**
     * 设置权限
     *
     * @param roleConfigMap
     * @param role
     */
    void setRoleByRoleConfigMap(Map<String, Integer> roleConfigMap, Role role) {
        //换电权限
        Integer roleId = role.getRoleId();
        role.setChangeBattery(roleConfigMap.get(roleId + "_" + RoleConfigConstant.MAIN_CHANGE_BATTERY));
        //调度权限
        role.setScheduling(roleConfigMap.get(roleId + "_" + RoleConfigConstant.MAIN_SCHEDULING));
        //开锁车权限
        role.setLockVehicle(roleConfigMap.get(roleId + "_" + RoleConfigConstant.MAIN_LOCK_VEHICLE));
        //操作距离权限
        role.setOperatingDistance(roleConfigMap.get(roleId + "_" + RoleConfigConstant.MAIN_OPERATING_DISTANCE));
        //查看车辆电池电量权限
        role.setLookBattery(roleConfigMap.get(roleId + "_" + RoleConfigConstant.MAIN_LOOK_BATTERY));
        //查看监管车辆
        role.setSuperviseMachine(roleConfigMap.get(roleId + "_" + RoleConfigConstant.SUPERVISE_MACHINE));
    }

    /**
     * @description: 根据当前登录用户，获取能获取的所有角色
     * @author: mo.shanyong
     * @date: 2025/3/4 16:02
     * @param: info 登录用户
     * @return: java.util.List<com.tbit.uqbike.object.pojo.Role>
     */
    @Override
    public List<Role> getRoleListByUser(LoginInfo info) {
        List<Integer> brandIdList = new ArrayList<>();
        //默认的
        brandIdList.add(0);
        if (!info.roleIsAdmin()){//非超级管理用户要加上，自己本身所在品牌的
            brandIdList.add(info.getBrandId());
        }
        //如果是超级管理员，只能看到品牌级以下的，不能看到超级管理员
        return roleDao.getByBrandIdAndLevel(brandIdList,String.valueOf(info.roleIsAdmin() ? Constants.BRAND_ROLE_LEVEL : info.getType()));
    }

    /**
     * 根据当前登录用户，获取当前登录用户可以创建的角色类型
     *
     * @param roleLevel 账户id(品牌Id、加盟商id、区域id)
     * @param roleLevel 角色等级
     * @param loginInfo 当前登录用户
     * @return 角色数据集合信息
     */
    @Override
    public List<Role> getRolesByLoginUser(Integer accountId,String roleLevel, LoginInfo loginInfo) {
        List<Role> roleList = roleDao.selectRolePermissionByUserId(loginInfo.getAccountUserId());
        List<Integer> accountIdList = new ArrayList<>(Collections.singletonList(accountId));
        if (CollectionUtils.isNotEmpty(roleList)){
            //如果当前用户的角色是系统默认角色，就可以返回系统默认的角色数据
            Role defaultRole = roleList.stream().filter(role -> {
                return Objects.equals(role.getAccountId(), Constants.SYSTEM_DEFAULT_ROLE_ACCOUNT_ID);
            }).findFirst().orElse(null);
            if (Objects.nonNull(defaultRole)){
                accountIdList.add(Constants.SYSTEM_DEFAULT_ROLE_ACCOUNT_ID);
            }
        }
        Map<String, Integer> map = getRoleConfigMap();
        List<Role> roles = roleDao.getRolesByaIdAndLevel(accountIdList,roleLevel);
        for (Role role1 : roles) {
            setRoleByRoleConfigMap(map, role1);
        }
        return roles;
    }
}
